package com.yycx.module.bus.provider.service.impl;

import com.yycx.bpm.provider.common.CommentTypeEnum;
import com.yycx.bpm.provider.service.ProcessInstanceService;
import com.yycx.common.base.entity.EntityMap;
import com.yycx.common.base.utils.FlymeUtils;
import com.yycx.common.constants.CommonConstants;
import com.yycx.common.mybatis.base.service.impl.BaseServiceImpl;
import com.yycx.common.mybatis.model.ResultBody;
import com.yycx.common.mybatis.query.CriteriaDelete;
import com.yycx.common.mybatis.query.CriteriaQuery;
import com.yycx.common.mybatis.query.CriteriaSave;
import com.yycx.common.mybatis.query.CriteriaUpdate;
import com.yycx.common.security.OpenHelper;
import com.yycx.common.security.OpenUser;
import com.yycx.common.utils.*;
import com.yycx.module.admin.client.entity.BaseUser;
import com.yycx.module.admin.provider.service.BaseRoleService;
import com.yycx.module.admin.provider.service.BaseUserService;
import com.yycx.module.bus.client.entity.*;
import com.yycx.module.bus.client.entity.hy.HyOrder;
import com.yycx.module.bus.client.enums.AmountTypeEnum;
import com.yycx.module.bus.client.enums.SaleTypeEnum;
import com.yycx.module.bus.provider.mapper.BusOrderMapper;
import com.yycx.module.bus.provider.service.*;
import com.yycx.module.file.provider.service.SysFileService;
import com.yycx.module.system.client.entity.SysBank;
import com.yycx.module.system.client.entity.SysCompany;
import com.yycx.module.system.provider.service.SysBankService;
import com.yycx.module.system.provider.service.SysCompanyService;
import lombok.AllArgsConstructor;
import org.flowable.engine.TaskService;
import org.flowable.engine.task.Comment;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 销售单接口实现类
 *
 * @author flyme
 * @date 2020-08-17
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class BusOrderServiceImpl extends BaseServiceImpl<BusOrderMapper, BusOrder> implements BusOrderService {


    @Autowired
    private BusDeptService deptService;
    @Autowired
    private OrderNoUtil orderNoUtil;
    @Autowired
    private BusOrderDetailsService orderDetailsService;

    @Autowired
    private BusPaymentService paymentService;

    @Autowired
    private SysBankService bankService;

    @Autowired
    private TaskService taskService;
    @Autowired
    private BaseUserService userService;

    @Autowired
    private BaseRoleService roleService;
    @Autowired
    private SysFileService fileService;

    @Autowired
    private BusDrugsService drugsService;

    @Autowired
    private SysCompanyService companyService;

    @Autowired
    private ProcessInstanceService processInstanceService;

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody beforePageList(CriteriaQuery<BusOrder> cq, BusOrder order, EntityMap requestMap) {
        OpenUser openUser = OpenHelper.getUser();
        String beginDate = requestMap.get("beginDate");
        String endDate = requestMap.get("endDate");
        cq.select(BusOrder.class, "*");
        cq.addSelect(BusSupplier.class, "supplierName");
        cq.addSelect(BusCustom.class, "customName", "settleType");
        cq.addSelect(BusSaleman.class, "saleManName");
        cq.addSelect(BusDept.class, "deptName", "reputation");
        cq.addSelect(BaseUser.class, "nickName");
        cq.addSelect(SysBank.class, "bankName");
        cq.like(BusOrder.class, "orderNo");
        cq.eq(BusOrder.class, "companyId", openUser.getCompanyId());
        cq.eq(BusOrder.class, "supplierId");
        cq.eq(BusOrder.class, "organizationId");
        cq.eq(BusOrder.class, "supplierBondType");
        cq.eq(BusOrder.class, "customBondType");
        if (FlymeUtils.isNotEmpty(beginDate)) {
            cq.ge(BusOrder.class, "sendDate", beginDate);
        }
        if (FlymeUtils.isNotEmpty(endDate)) {
            cq.le(BusOrder.class, "sendDate", endDate);
        }
        cq.eq(BusOrder.class, "delivery");
        cq.eq(BusOrder.class, "reputationType");
        cq.eq(BusOrder.class, "supplierReputationType");
        cq.eq(BusOrder.class, "customId");
        cq.eq(BusOrder.class, "deptId");
        cq.eq(BusOrder.class, "salesmanId");
        cq.eq(BusOrder.class, "billsType");
        cq.eq(BusOrder.class, "sendState");
        cq.eq(BusOrder.class, "billsStatus");
        cq.like(BusSupplier.class, "supplierName");
        cq.like(BusCustom.class, "customName");
        cq.createJoin(BusSaleman.class);
        cq.createJoin(BusCustom.class);
        cq.createJoin(BusSupplier.class);
        cq.createJoin(BusDept.class);
        cq.createJoin(BaseUser.class);
        cq.createJoin(SysBank.class);
        cq.createJoin(BusOrderDetails.class).setMainField("orderId").setJoinField("orderId");
        cq.groupBy("ord.orderId");
        return ResultBody.ok();
    }

    @Override
    public List<EntityMap> afterPageList(CriteriaQuery<BusOrder> cq, List<EntityMap> data, ResultBody resultBody) {
        for (EntityMap map : data) {
            Long orderId = map.getLong("orderId");

            Integer customBondType = map.getInt("customBondType");
            List<BusOrderDetails> orderDetailsList = orderDetailsService.selectByOrderId(orderId);
            BigDecimal saleAmount = new BigDecimal("0");
            BigDecimal saleNum = new BigDecimal("0");
            BigDecimal customOverBond = new BigDecimal("0");
            if (FlymeUtils.isNotEmpty(orderDetailsList)) {
                for (BusOrderDetails orderDetails : orderDetailsList) {
                    saleAmount = saleAmount.add(FlymeUtils.getBigDecimal(orderDetails.getSaleAmount(), "0"));
                    Integer saleType = Integer.parseInt(orderDetails.getSaleType());
                    if (!SaleTypeEnum.Pz.getCode().equals(saleType)) {
                        saleNum = saleNum.add(FlymeUtils.getBigDecimal(orderDetails.getSaleNum(), "0"));
                    }
                    customOverBond = customOverBond.add(FlymeUtils.getBigDecimal(orderDetails.getCustomOverBond(), "0"));
                }
                BusOrderDetails orderDetails = orderDetailsList.get(0);
                Long drugId = orderDetails.getDrugsId();
                BusDrugs busDrugs = drugsService.getById(drugId);
                if (FlymeUtils.isNotEmpty(busDrugs)) {
                    map.put("drugsSpec", busDrugs.getDrugsSpec());
                    map.put("drugsName", busDrugs.getDrugsName());
                }

            }
            map.put("saleAmount", saleAmount);
            map.put("saleNum", saleNum);
            if (customBondType > 0 && customBondType != 5 && customBondType != 7) {
                if (FlymeUtils.nezero(customOverBond)) {
                    map.put("overAmount", customOverBond);
                }
            }
        }
        return super.afterPageList(cq, data, resultBody);
    }

    @Override
    public ResultBody beforeAdd(CriteriaSave cs, BusOrder order, EntityMap extra) {
        Long deptId = order.getDeptId();
        ApiAssert.isNotEmpty("部门ID不能为空", deptId);
        Integer customBondType = order.getCustomBondType();

        BusDept busDept = deptService.getById(deptId);
        Long companyId = busDept.getCompanyId();
        order.setCompanyId(companyId);
        order.setOrganizationId(busDept.getOrganizationId());
        order.setSaleManId(busDept.getSalemanId());
        order.setRevokeState(CommonConstants.INT_0);
        if (customBondType.equals(0)) {
            //全款
            order.setDelivery(1);
            order.setTakeAmount(new BigDecimal("0"));
        } else {
            //资信额度
            BigDecimal reputationAmount = busDept.getReputationAmount();
            ApiAssert.gtzero("资信额度未配置", reputationAmount);
            BigDecimal userReputationAmount = FlymeUtils.getBigDecimal(orderDetailsService.totalReputationAmount(deptId), "0");
            //总额度-已用额度
            BigDecimal noUserAmount = reputationAmount.subtract(userReputationAmount);
            ApiAssert.gezero("资信额度不足", noUserAmount);
            order.setDelivery(2);
        }
        Long userId = OpenHelper.getUserId();
        String orderNo = getOrderNo(companyId, userId);
        order.setOrderNo(orderNo);
        order.setOrderType(SaleTypeEnum.Xs.getCode());
        //未提交
        order.setOrderState(CommonConstants.INT_0);
        order.setUserId(OpenHelper.getUserId());
        return ResultBody.ok();
    }


    /**
     * 按月从001开始生成序列号
     */
    public String getOrderNo(Long companyId, Long userId) {
        String date = DateUtils.formatDate(DateUtils.getNowDate(), "MMdd");
        String year = DateUtils.getYear();
        String orderNoPrefix = year + date + companyId;
        //加锁避免重复
        RLock lock = redisLock.lock(userId);
        String result = null;
        try {
            CriteriaQuery<BusOrder> cq = new CriteriaQuery(BusOrder.class);
            cq.select("orderId", "orderNo");
            cq.eq(true, "companyId", companyId);
            cq.likeRight(true, "orderNo", year);
            cq.orderByDesc("createTime");
            cq.limit(1);
            BusOrder order = getOne(cq);
            if (FlymeUtils.isEmpty(order)) {
                return orderNoPrefix + "0001";
            }
            String lastOrderNo = order.getOrderNo();

            lastOrderNo = lastOrderNo.substring(9);

            result = orderNoPrefix + String.format("%04d", Long.parseLong(lastOrderNo) + 1);
        } finally {
            redisLock.unlock(lock);
        }
        return result;
    }

    @Override
    public ResultBody beforeEdit(CriteriaUpdate<BusOrder> cu, BusOrder busOrder, EntityMap extra) {
        Long deptId = busOrder.getDeptId();
        Integer customBondType = busOrder.getCustomBondType();
        if (FlymeUtils.isNotEmpty(deptId)) {
            BusDept busDept = deptService.getById(deptId);
            busOrder.setSaleManId(busDept.getSalemanId());
        }
        if (customBondType.equals(0)) {
            busOrder.setDelivery(1);
        } else {
            busOrder.setDelivery(2);
        }
        return super.beforeEdit(cu, busOrder, extra);
    }

    @Override
    public ResultBody afterEdit(CriteriaUpdate cu, BusOrder busOrder, EntityMap extra) {
        orderDetailsService.updateByOrder(busOrder);
        return super.afterEdit(cu, busOrder, extra);
    }


    @Override
    public ResultBody afterAdd(CriteriaSave cs, BusOrder busOrder, EntityMap extra) {
        Integer delivery = busOrder.getDelivery();
        BigDecimal takeAmount = FlymeUtils.getBigDecimal(busOrder.getTakeAmount(), "0");
        if (delivery.equals(2) && FlymeUtils.gtzero(takeAmount)) {
            //添加保证金认款单
            paymentService.addCustomBondPayment(busOrder, CommonConstants.INT_2);
        }
        return super.afterAdd(cs, busOrder, extra);
    }

    @Override
    public Boolean updateSendState(Long orderId, Integer sendState) {
        CriteriaUpdate cu = new CriteriaUpdate();
        cu.set(true, "sendState", sendState);
        cu.eq(true, "orderId", orderId);
        return update(cu);
    }

    @Override
    public Boolean updateOrderState(Long orderId, String processInstanceId, Integer orderState) {
        CriteriaUpdate cu = new CriteriaUpdate();
        cu.set(true, "orderState", orderState);
        cu.set(true, "processInstanceId", processInstanceId);
        cu.eq(true, "orderId", orderId);
        return update(cu);
    }


    @Override
    public Boolean updateOrderState(Long orderId, Integer orderState) {
        CriteriaUpdate cu = new CriteriaUpdate();
        cu.set(true, "orderState", orderState);
        cu.eq(true, "orderId", orderId);
        return update(cu);
    }

    @Override
    public Boolean updateSendInfo(Long orderId, String sendNo, String invoiceAttachment, String sendAttachment, Long customFpId) {
        CriteriaUpdate cu = new CriteriaUpdate();
        cu.set(true, "sendNo", sendNo);
        cu.set(true, "invoiceAttachment", invoiceAttachment);
        cu.set(true, "sendAttachment", sendAttachment);
        cu.set(true, "customFpId", customFpId);
        cu.eq(true, "orderId", orderId);
        return update(cu);
    }


    @Override
    public Boolean updateSupplierId(Long orderId, Long supplierId) {
        CriteriaUpdate cu = new CriteriaUpdate();
        cu.set(true, "supplierId", supplierId);
        cu.eq(true, "orderId", orderId);
        return update(cu);
    }

    @Override
    public Boolean updatePrintTag(Long orderId) {
        CriteriaUpdate cu = new CriteriaUpdate();
        cu.set(true, "printTag", CommonConstants.ENABLED);
        cu.eq(true, "orderId", orderId);
        return update(cu);
    }

    @Override
    public ResultBody beforeGet(CriteriaQuery<BusOrder> cq, BusOrder busOrder, EntityMap requestMap) {
        cq.select(BusOrder.class, "*");
        cq.addSelect("sum(bod.saleAmount) saleAmount", "bod.saleType", "sum(bod.customOverBond) customOverBond");
        cq.select(BusCustom.class, "customName", "settleType");
        cq.select(BusSupplier.class, "supplierName");
        cq.createJoin(BusOrderDetails.class).setMainField("orderId").setJoinField("orderId");
        cq.createJoin(BusCustom.class);
        cq.createJoin(BusSupplier.class);
        cq.groupBy("bod.orderId");
        return super.beforeGet(cq, busOrder, requestMap);
    }

    @Override
    public void afterGet(CriteriaQuery cq, EntityMap result) {
        Long orderId = result.getLong("orderId");
        Long paymentId = cq.getLong("paymentId");
        if (FlymeUtils.isNotEmpty(orderId)) {
            List<EntityMap> fileList = fileService.selectFileListByFileType(orderId.toString(), "Order", "");
            result.put("orderImage", fileList);
            if (FlymeUtils.isNotEmpty(paymentId)) {
                List<EntityMap> paymentImage = fileService.selectFileListByFileType(paymentId.toString(), "BusPayment", "");
                result.put("paymentImage", paymentImage);
            }
        }
        super.afterGet(cq, result);
    }

    @Override
    public ResultBody beforeDelete(CriteriaDelete<BusOrder> cd) {


        return super.beforeDelete(cd);
    }

    @Override
    public ResultBody afterDelete(CriteriaDelete cd, Serializable[] ids) {
        EntityMap map = cd.getRequestMap();
        Serializable orderId = cd.getIdValue();
        //删除订单明细
        orderDetailsService.delByOrderId(orderId);
        //删除保证金认款单
        paymentService.removeByOrderId(AmountTypeEnum.CustomBond, orderId.toString());
        //删除回款审批单
        paymentService.removeByOrderId(AmountTypeEnum.CbReturn, orderId.toString());
        //流程实例ID
        String processInstanceId = map.get("processInstanceId");
        //删除流程数据
        if (FlymeUtils.isNotEmpty(processInstanceId)) {
            processInstanceService.delete(processInstanceId, true, null, "删除");
        }
        return super.afterDelete(cd, ids);
    }

    /**
     * 查询订单信息
     *
     * @param orderId
     * @return
     */
    @Override
    public EntityMap getMapByOrderId(Long orderId) {
        CriteriaQuery cq = new CriteriaQuery(BusOrder.class);
        cq.select(BusOrder.class, "orderNo", "sendDate", "customBondType", "orderType", "supplierBondType", "takeAmount", "takeDate", "delivery", "deptId", "bankId", "remark", "processInstanceId", "userId", "printTag", "companyId");
        cq.select(BusSupplier.class, "supplierName");
        cq.select(BusSaleman.class, "saleManName");
        cq.select(BusCustom.class, "customName");
        cq.select(BaseUser.class, "nickName");
        cq.select(BusDept.class, "deptName");
        cq.eq(BusOrder.class, "orderId", orderId);
        cq.createJoin(BusSupplier.class);
        cq.createJoin(BusCustom.class);
        cq.createJoin(BusDept.class);
        cq.createJoin(BusSaleman.class);
        cq.createJoin(BaseUser.class);
        return findOne(cq);
    }

    /**
     * 获取订单打印信息
     *
     * @param orderId
     * @return
     */
    @Override
    public ResultBody getPrintInfo(Long orderId) {
        EntityMap orderMap = getMapByOrderId(orderId);
        List orderDetails = orderDetailsService.getOrderDetails(orderId);
        Long deptId = orderMap.getLong("deptId");
        String processInstanceId = orderMap.get("processInstanceId");
        Long bankId = orderMap.getLong("bankId");
        Integer delivery = orderMap.get("delivery", 1);
        BusDept dept = deptService.getById(deptId);
        SysBank bank = bankService.getById(bankId);
        BaseUser user = userService.getById(orderMap.getLong("userId"));
        Long companyId = orderMap.getLong("companyId");
        SysCompany company = companyService.getById(companyId);
        orderMap.put("companyName", company.getCompanyName());
        orderMap.put("sendType", "货票同行");
        orderMap.put("deliveryTitle", "发货方式");
        //制单人
        orderMap.put("nickName", user.getNickName());
        if (FlymeUtils.isNotEmpty(bank) && delivery.equals(2)) {
            orderMap.put("bankName", bank.getBankName());
        }
        if (delivery.equals(2)) {
            orderMap.put("deliveryTitle", "资信天数");
            if (FlymeUtils.isNotEmpty(dept)) {
                orderMap.put("deliveryValue", dept.getReputation() + "天");
            }
        } else {
            BigDecimal saleAmount = orderDetailsService.totalSaleAmount(orderId);
            orderMap.put("deliveryValue", "全款");
            orderMap.put("bankName", "客户付");
            orderMap.put("takeAmount", saleAmount);
        }
        Integer invoiceSendType = orderMap.getInt("invoiceSendType");
        if (invoiceSendType.equals(2)) {
            orderMap.put("sendType", "单独邮寄");
        }
        orderMap.put("orderDetails", orderDetails);
        if (FlymeUtils.isNotEmpty(processInstanceId)) {
            //查询审批人
            List<Comment> list = taskService.getProcessInstanceComments(processInstanceId, CommentTypeEnum.WC.toString());
            if (FlymeUtils.isNotEmpty(list)) {
                list = list.stream().filter(ConvertUtils.distinctByKey(Comment::getUserId)).collect(Collectors.toList());
                int i = 1;
                for (Comment comment : list) {
                    String userId = comment.getUserId();
                    BaseUser baseUser = userService.getUserById(Long.parseLong(userId));
                    List<String> roleCodes = roleService.selectRoleCodesByUserId(baseUser.getUserId());
                    if (roleCodes.contains("ROLE_NQBZ") || roleCodes.contains("ROLE_NQBZ_LD")) {
                        orderMap.put("nickName_nqbz", baseUser.getNickName());
                    }
                    if (roleCodes.contains("ROLE_CGBZ") || roleCodes.contains("ROLE_CGBZ_LD")) {
                        orderMap.put("nickName_nqbz", baseUser.getNickName());
                    }
                    if (roleCodes.contains("ROLE_CWBZ") || roleCodes.contains("ROLE_CWBZ_LD")) {
                        orderMap.put("nickName_cwbz", baseUser.getNickName());
                    }
                    if (roleCodes.contains("ROLE_ZJL") || roleCodes.contains("ROLE_ZJL_LD")) {
                        String nickName = baseUser.getNickName();
                        if (nickName.equals("寇新利") || nickName.equals("马爱梅")) {
                            orderMap.put("map_zjl", baseUser.getNickName());
                        }
                        orderMap.put("nickName_zjl", baseUser.getNickName());
                    }
                    if (roleCodes.contains("ROLE_KJ") || roleCodes.contains("ROLE_KJ_LD")) {
                        orderMap.put("nickName_kj", baseUser.getNickName());
                    }
                    if (FlymeUtils.isNotEmpty(orderMap.get("map_zjl"))) {
                        orderMap.put("nickName_zjl", "寇新利");
                    }

                }
            }
        }
        return ResultBody.ok(orderMap);
    }

    @Override
    public ResultBody totalCount() {
        CriteriaQuery<BusOrderDetails> cq = new CriteriaQuery(BusOrderDetails.class);
        cq.select("count(DISTINCT orderId) orderCount", "sum(saleAmount) totalAmount", "sum(settleAmount+settleAmount2) totalSettleAmount", "sum(settleRealAmount+settleRealAmount2) totalSettleRealAmount", "sum(supplierRetable) totalSupplierRetable", "sum(supplierRealAmount) totalSupplierRealAmount");
        cq.eq(BusOrderDetails.class, "companyId", OpenHelper.getCompanyId());
        cq.eq(BusOrderDetails.class, "orderDetailsState", CommonConstants.INT_1);
        EntityMap result = orderDetailsService.findOne(cq);
        return ResultBody.ok(result);
    }

    @Override
    public List<Long> selectOrderId(Long orderId) {
        CriteriaQuery<BusOrder> cq = new CriteriaQuery(BusOrder.class);
        cq.select("orderId");
        cq.nested(e -> e.eq(true, "orderId", orderId).or().eq(true, "parentId", orderId));
        return listObjs(cq, e -> Long.parseLong(e.toString()));
    }


}
